import { useState, useEffect, useRef } from 'react'
/* -------------------------------------------------------- antd -- */
import { Tree } from 'antd'
/* -------------------------------------------------------- Declare -- */
const { $fn } = window

const updateTreeData = (data, value, children) => data.map( node => {
	if (node.value === value) {
		return { ...node, children }
	}
	if (node.children) {
		return {
			...node,
			children: updateTreeData( node.children, value, children )
		}
	}
	return node
})
const getExpandKeys = data => {
	let keys = []
	const deep = data => {
		data.forEach( ({ children, id }) => {
			if( children ){
				keys.push( id )
				deep(children)
			}
		})
	}
	deep(data)
	return keys
}
/* -------------------------------------------------------- 回到顶部 -- */
const Index = ({ 
	className,						/** @param {String}				# 盒子 className */
	style, 							/** @param {String}				# 盒子 style */
	// size='small', 					/** @param {String}				# 大小 */
	name, 							/** @param {String}				# name */
	p,								/** @param {String}				# 提示语 */
	hint='请选择',					/** @param {String}				# 提示语 */
	label='',						/** @param {String}				# 标签名 */
	width,							/** @param {String}				# 宽度 */
	height,							/** @param {String}				# 高度 */
	out,							/** @param {Number}				# 在外部设置 value */
	mul,							/** @param {Boolan, Number}		# 是否多选 */
	check,							/** @param {Boolan}				# 是否多选框选择 */
	expand,							/** @param {Boolan, Number}		# 是否展开树 */
	mode,							/** @param {Boolan}				# 选择模式: menu */
	//
	value,							/** @param {String}				# 值 */
	disabled,						/** @param {Boolan}				# 禁用 */
	// 获取值
	onChange,						/** @param {Event}				# 有 Form 时值改变时执行 */
	onChanged,						/** @param {Event}				# 值改变时执行 */
	// 自定义扩展
	antd = {},						/** @param {Object}				# antd */
	// data
	api,							/** @param {String}				# 获取数据的 api */
	param,							/** @param {Object}				# api 参数 */
	paging,							/** @param {Object}				# 是否分页*/
	data,							/** @param {Array}				# 数据 */
	idStr='id',						/** @param {String}				# 提交字段名 */
	nameStr='title',				/** @param {String}				# 显示字段名 */
	cache,							/** @param {Boolan}				# 是否缓存 */
	perm,							/** @param {Boolan}				# 是否有权限 */
}, ref)=> {// eslint-disable-line
	const onceRef = useRef(0)
	const keysRef = useRef([])
	const getValue = value => mode === 'menu' || $fn.isObject(value)  ? value?.value ?? [] : value
	let v = check || mul ? ( value ? value : []) : value ? value : ''
	const [expandedKeys, setExpandedKeys] = useState([])
	const [autoExpandParent, setAutoExpandParent] = useState(true)
	let [ model, setModel ] = useState( getValue(v) )
	let [ ajax, setAjax ] = useState( data )
	
	p = p ? p : hint + label
	let isLazy = Array.isArray(api)
	
	antd = { 
		className, 
		disabled,
		placeholder: p, 
		checkable: check,
		// showLine:true
		selectable:false,
		multiple: mul,
		checkStrictly:false,
		checkedKeys: Array.isArray(model) ? model : [],
		expandedKeys,
		autoExpandParent, 						// 是否自动展开父节点
		// defaultExpandParent: true, 				// 默认展开父节点
		// defaultExpandedKeys: [0],				// 默认展开指定的树节点
		// defaultCheckedKeys: [0],					// 默认展开指定的树节点
		// defaultSelectedKeys:[], 					// 默认选中的树节点 => title 
		// defaultExpandAll: true,					// 默认展开所有树节
		fieldNames: { label:nameStr, key: idStr, children:'children' },	// 自定义字段
		treeData : ajax,
		virtual: ajax?.length > 30,
		style,
		onExpand: value => {
			setExpandedKeys( value )
			setAutoExpandParent(false)
		},
		onCheck: (value, evt) => {
			onceRef.current = 1
			if(!out){ setModel( value ) }
			if( mode === 'menu' ){
				const { halfCheckedKeys } = evt
				const val = { parent:halfCheckedKeys, value }
				const result = name ? { model: {[name]: val} } : null
				onChange?.( val )
				onChanged?.({ value: val, ...result  })
			}else{
				const result = name ? { model: {[name]: value} } : null
				onChange?.( value )
				onChanged?.({ value, ...result  })
			}
		},
		loadData: isLazy ? ({value, pos, children}) => {
			const index = pos.split('-').length - 1;
			return new Promise( resolve =>{
				if (children) {
					resolve()
					return
				}
				window.$http.pull(null, api[index], { id: value }).then( data =>{
					if(index === api.length - 1){
						data.forEach(v => v.isLeaf = true )
					}
					setAjax( v => updateTreeData( v, value, data ) )
					resolve()
				})
			})
		} : null,
		...antd
	}
	
	useEffect(()=> { 
		if( !out ) {
			if( onceRef.current === 0 ){
				if(mode === 'menu' || $fn.isObject(value)){
					setTimeout(()=>{
						setModel( value?.value ?? [] )
						if(expand === 2) setExpandedKeys( [...(value?.value ?? []), ...(value?.parent??[])] )					
					},200)
				}else{
					setModel( value )
					if(expand === 2) setExpandedKeys( value )
				}
			}
		}
	}, [ value ]) // eslint-disable-line
	
	const getCRUD = data => {
		const deep = d => {
			d.forEach( v => {
				if( v.children ){
					if( v.children[0].title !== '查' ) {
						deep(v.children)
					}
				}else{
					v.children = [
						{ title:'查', id: v.id + '_r' },
						{ title:'增', id: v.id + '_c' },
						{ title:'改', id: v.id + '_u' },
						{ title:'删', id: v.id + '_d' },
						{ title:'其它', id: v.id + '_o' }
					]
				}
			} )
			return d
		}
		return deep(data)
	}
	
	useEffect(() => { 
		$fn.ajax({setAjax, data:ajax, api: isLazy ? api[0] : api, cache, paging, param, setData:d=>{
			return perm ? getCRUD(d) : d
		}}).then(data=>{
			let keys = []
			if(expand === 1 ){
				keys = getExpandKeys(data)
				keysRef.current = keys
			}else if( expand === 0){
				keys = [0]
			}
			setExpandedKeys( keys )
		})
	}, []) // eslint-disable-line
	
	useEffect(()=> {
		if(keysRef.current && onceRef.current === 0){
			let keys = []
			if(expand === 0 ){
				keys = [0]
			}else if( expand === 1){
				keys = [keysRef.current]
			}else if( expand === 2){
				keys = mode === 'menu' || $fn.isObject(value) ? [ ...(value?.value ?? []), ...(value?.parent ?? []) ] : value
			}
			setExpandedKeys( keys )
		}
	}, [ expand, value ]) // eslint-disable-line
	
	return <div style={{width,height}} className={ $fn.isNumber(height) ? 'scrollbar oys':''}><Tree {...antd} /></div>
}

export default Index